{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "06a3bbec",
   "metadata": {},
   "source": [
    "下面用代码实现循环神经网络。首先读取数据，使用《小王子》这本书作为训练语料。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "58df11c1",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "115\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "\n",
    "# 导入前面实现的小王子数据集\n",
    "sys.path.append('./code')\n",
    "from utils import TheLittlePrinceDataset\n",
    "\n",
    "dataset = TheLittlePrinceDataset()\n",
    "\n",
    "# 统计每句话的长度\n",
    "sent_lens = []\n",
    "max_len = -1\n",
    "for sentence in dataset.tokens:\n",
    "    sent_len = len(sentence)\n",
    "    sent_lens.append(sent_len)\n",
    "    if sent_len > max_len:\n",
    "        max_len = sent_len\n",
    "        longest = sentence\n",
    "print(max_len)\n",
    "\n",
    "# 简单看一下语料中序列长度的分布\n",
    "import matplotlib.pyplot as plt\n",
    "plt.hist(sent_lens, bins=20)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf1e69d9",
   "metadata": {},
   "source": [
    "接下来建立词表，截断过长的序列，将序列填充（padding）到相同长度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f25456ee",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1089 115\n",
      "(1088, 40)\n",
      "[  4  16  19 733 734 735 733 734 735   2  63  20   9   1   1   2   1  10\n",
      " 736 737   4  16  19  21   1   2  30 371 209  33 294   3   0   0   0   0\n",
      "   0   0   0   0]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "dataset.build_vocab()\n",
    "sent_tokens = dataset.convert_tokens_to_ids()\n",
    "# 截断和填充\n",
    "max_len=40\n",
    "for i, tokens in enumerate(sent_tokens):\n",
    "    tokens = tokens[:max_len]\n",
    "    tokens += [dataset.token2id['<pad>']] * (max_len - len(tokens))\n",
    "    sent_tokens[i] = tokens\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "\n",
    "print(len(dataset.tokens), max([len(x) for x in dataset.tokens]))\n",
    "print(sent_tokens.shape)\n",
    "print(sent_tokens[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "06e6fb52",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "import torch\n",
    "from torch import nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "# 定义一个正态分布的函数用于初始化参数\n",
    "def normal(shape):\n",
    "    return torch.randn(size=shape) * 0.01\n",
    "\n",
    "class RNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(RNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 将输入与隐状态分别经过线性变化后相加\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            # 输入hidden_state与inputs经过线性变换后相加，\n",
    "            # 输出的hidden_state也是下一时刻输入的hidden_state\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        # 返回所有时刻的hidden_state: seq_len * batch_size * hidden_size\n",
    "        # 以及最后时刻的hidden_state（可能用于后续输入）: \n",
    "        # batch_size * hidden_size\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state,)\n",
    "\n",
    "# 在循环神经网络的基础上添加语言模型的输入输出、损失计算等\n",
    "class RNNLM(nn.Module):\n",
    "    def __init__(self, model, vocab_size, hidden_size):\n",
    "        super(RNNLM, self).__init__()\n",
    "        self.vocab_size = vocab_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.embedding = nn.Embedding(vocab_size, hidden_size)\n",
    "        self.model = model\n",
    "        self.W_hq = nn.Parameter(normal((hidden_size, vocab_size)))\n",
    "        self.b_q = nn.Parameter(torch.zeros(vocab_size))\n",
    "        \n",
    "    def forward(self, input_ids):\n",
    "        batch_size, seq_len = input_ids.shape\n",
    "        # input_ids形状为batch_size * seq_len，翻转为seq_len * batch_size，\n",
    "        # 将seq_len放在第一维方便计算\n",
    "        input_ids = torch.permute(input_ids, (1, 0))\n",
    "        # seq_len * batch_size * embed_size\n",
    "        embed = self.embedding(input_ids)\n",
    "        # batch_size * hidden_size\n",
    "        states = self.model.init_rnn_state(batch_size, self.hidden_size)\n",
    "        hiddens, _ = self.model(embed, states)\n",
    "    \n",
    "        hiddens = torch.flatten(hiddens[:-1], start_dim=0, end_dim=1)\n",
    "        output_states = torch.mm(hiddens, self.W_hq) + self.b_q\n",
    "        labels = torch.flatten(input_ids[1:], start_dim=0, end_dim=1)\n",
    "        loss_fct = nn.CrossEntropyLoss(ignore_index=0)\n",
    "        loss = loss_fct(output_states, labels)\n",
    "        return loss"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45a010aa",
   "metadata": {},
   "source": [
    "下面展示使用梯度裁剪的循环神经网络语言模型的训练代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "760da2e1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1088, 40)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.3988: 100%|█| 200/200 [04:28<00:00,  1.34s\n"
     ]
    },
    {
     "data": {
      "image/png": "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Ypg8eTIpKSn07NmzrctslunTpzu+HzJkCGPGjKFbt2588MEH+Pj4OLGy1vHmm28yffp0YmNjHc+15/vX2dXU1HDDDTdgmiYLFy5scOzRRx91fD9kyBA8PT352c9+xrx589rFUu033XST4/vBgwczZMgQevbsyapVq5g8ebITK2sd//znP7nlllvw9vZu8Hx7uY+n+3xwBer6OUl4eDhubm6njGjOyckhOjraSVW1jAcffJAvvviClStXEhcXd8Zzx4wZA0BycnJblNaigoOD6dOnD8nJyURHR1NdXU1hYWGDc9rr/Tx8+DDLli3j7rvvPuN57fn+AY57c6Z/h9HR0acMcK+traWgoKDd3Ft7SDl8+DBLly5t0JrSmDFjxlBbW0taWlrbFNjCEhISCA8Pd/y97Aj30O77778nKSnprP82wTXv4+k+H5ryOzQ6OrrRf6v2Yy1BQeUknp6ejBgxguXLlzues1qtLF++nMTERCdWdu5M0+TBBx/kk08+YcWKFfTo0eOsr9mxYwcAMTExrVxdyystLSUlJYWYmBhGjBiBh4dHg/uZlJREenp6u7yfb731FpGRkVx++eVnPK893z+AHj16EB0d3eC+FRcXs3HjRsd9S0xMpLCwkK1btzrOWbFiBVar1RHUXJk9pBw8eJBly5YRFhZ21tfs2LEDi8VySndJe3HkyBHy8/Mdfy/b+z082ZtvvsmIESMYOnToWc91pft4ts+HpvwOTUxMZNeuXQ1Cpz14DxgwoMUKlZO89957ppeXl7lo0SJz79695r333msGBwc3GNHcntx///1mUFCQuWrVKjMrK8vxVV5ebpqmaSYnJ5u///3vzS1btpipqanmp59+aiYkJJgTJkxwcuVN89hjj5mrVq0yU1NTzbVr15pTpkwxw8PDzdzcXNM0TfO+++4zu3btaq5YscLcsmWLmZiYaCYmJjq56uarq6szu3btas6dO7fB8+31/pWUlJjbt283t2/fbgLmCy+8YG7fvt0x6+XZZ581g4ODzU8//dTcuXOnOXPmTLNHjx5mRUWF4z2mTZtmDhs2zNy4caO5Zs0as3fv3ubs2bOddUkNnOn6qqurzauuusqMi4szd+zY0eDfpX2WxLp168wXX3zR3LFjh5mSkmL+5z//MSMiIszbbrvNyVd2wpmusaSkxHz88cfN9evXm6mpqeayZcvM4cOHm7179zYrKysd7+HK99A0z/731DRNs6ioyPT19TUXLlx4yutd/T6e7fPBNM/+O7S2ttYcNGiQedlll5k7duwwv/nmGzMiIsJ88sknW6xOBZVGvPrqq2bXrl1NT09Pc/To0eaGDRucXdI5Axr9euutt0zTNM309HRzwoQJZmhoqOnl5WX26tXLfOKJJ8yioiLnFt5EN954oxkTE2N6enqaXbp0MW+88UYzOTnZcbyiosJ84IEHzJCQENPX19ecNWuWmZWV5cSKz82SJUtMwExKSmrwfHu9fytXrmz07+Xtt99umqZtivJvf/tbMyoqyvTy8jInT558yrXn5+ebs2fPNv39/c3AwEDzzjvvNEtKSpxwNac60/Wlpqae9t/lypUrTdM0za1bt5pjxowxg4KCTG9vb7N///7mn//85wYf8s52pmssLy83L7vsMjMiIsL08PAwu3XrZt5zzz2n/IfPle+haZ7976lpmuYbb7xh+vj4mIWFhae83tXv49k+H0yzab9D09LSzOnTp5s+Pj5meHi4+dhjj5k1NTUtVqdRX6yIiIiIy9EYFREREXFZCioiIiLishRURERExGUpqIiIiIjLUlARERERl6WgIiIiIi5LQUVERERcloKKiIiIuCwFFRFpku7du/PSSy81+fxVq1ZhGMYpG5p1VM398xGRpnF3dgEi0jomTZrEBRdc0GIfnps3b8bPz6/J51944YVkZWURFBTUIj9fRDonBRWRTsw0Terq6nB3P/uvgoiIiGa9t6enZ4tt8y4inZe6fkQ6oDvuuIPVq1fz8ssvYxgGhmGQlpbm6I75+uuvGTFiBF5eXqxZs4aUlBRmzpxJVFQU/v7+jBo1imXLljV4zx93bRiGwT/+8Q9mzZqFr68vvXv35rPPPnMc/3HXz6JFiwgODmbJkiX0798ff39/pk2bRlZWluM1tbW1PPTQQwQHBxMWFsbcuXO5/fbbufrqq894vWvWrGH8+PH4+PgQHx/PQw89RFlZWYPa//CHPzB79mz8/Pzo0qULCxYsaPAe6enpzJw5E39/fwIDA7nhhhvIyclpcM7nn3/OqFGj8Pb2Jjw8nFmzZjU4Xl5ezk9/+lMCAgLo2rUrf/vb385Yt4icnYKKSAf08ssvk5iYyD333ENWVhZZWVnEx8c7jv/qV7/i2WefZd++fQwZMoTS0lJmzJjB8uXL2b59O9OmTePKK68kPT39jD/nd7/7HTfccAM7d+5kxowZ3HLLLRQUFJz2/PLycp5//nn+/e9/891335Gens7jjz/uOP5///d//Pe//+Wtt95i7dq1FBcXs3jx4jPWkJKSwrRp07j22mvZuXMn77//PmvWrOHBBx9scN78+fMZOnQo27dv51e/+hUPP/wwS5cuBcBqtTJz5kwKCgpYvXo1S5cu5dChQ9x4442O13/55ZfMmjWLGTNmsH37dpYvX87o0aMb/Iy//OUvjBw5ku3bt/PAAw9w//33k5SUdMb6ReQsWmwfZhFxKRMnTjQffvjhBs/Zt61fvHjxWV8/cOBA89VXX3U87tatm/niiy86HgPmb37zG8fj0tJSEzC//vrrBj/r+PHjpmma5ltvvWUCZnJysuM1CxYsMKOiohyPo6KizPnz5zse19bWml27djVnzpx52jrvuusu8957723w3Pfff29aLBazoqLCUfu0adManHPjjTea06dPN03TNL/99lvTzc3NTE9Pdxzfs2ePCZibNm0yTdM0ExMTzVtuueW0dXTr1s38yU9+4nhstVrNyMhIc+HChad9jYicnVpURDqhkSNHNnhcWlrK448/Tv/+/QkODsbf3599+/adtUVlyJAhju/9/PwIDAwkNzf3tOf7+vrSs2dPx+OYmBjH+UVFReTk5DRopXBzc2PEiBFnrOGHH35g0aJF+Pv7O76mTp2K1WolNTXVcV5iYmKD1yUmJrJv3z4A9u3bR3x8fINWpwEDBhAcHOw4Z8eOHUyePPmMtZz852EYBtHR0Wf88xCRs9NgWpFO6Mezdx5//HGWLl3K888/T69evfDx8eG6666jurr6jO/j4eHR4LFhGFit1madb5pmM6tvqLS0lJ/97Gc89NBDpxzr2rXreb33yXx8fM56TnP/PETk7NSiItJBeXp6UldX16Rz165dyx133MGsWbMYPHgw0dHRpKWltW6BPxIUFERUVBSbN292PFdXV8e2bdvO+Lrhw4ezd+9eevXqdcqXp6en47wNGzY0eN2GDRvo378/AP379ycjI4OMjAzH8b1791JYWMiAAQMAW2vJ8uXLz/s6RaR51KIi0kF1796djRs3kpaWhr+/P6Ghoac9t3fv3nz88cdceeWVGIbBb3/7W6e0BPz85z9n3rx59OrVi379+vHqq69y/PhxDMM47Wvmzp3L2LFjefDBB7n77rvx8/Nj7969LF26lNdee81x3tq1a3nuuee4+uqrWbp0KR9++CFffvklAFOmTGHw4MHccsstvPTSS9TW1vLAAw8wceJERzfZ008/zeTJk+nZsyc33XQTtbW1fPXVV8ydO7d1/1BEOjm1qIh0UI8//jhubm4MGDCAiIiIM443eeGFFwgJCeHCCy/kyiuvZOrUqQwfPrwNq7WZO3cus2fP5rbbbiMxMdEx3sTb2/u0rxkyZAirV6/mwIEDjB8/nmHDhvHUU08RGxvb4LzHHnuMLVu2MGzYMP74xz/ywgsvMHXqVMDWRfPpp58SEhLChAkTmDJlCgkJCbz//vuO10+aNIkPP/yQzz77jAsuuIBLLrmETZs2tc4fhIg4GOb5dhCLiLQSq9VK//79ueGGG/jDH/5wzu/TvXt3HnnkER555JGWK05E2oS6fkTEZRw+fJhvv/2WiRMnUlVVxWuvvUZqaio333yzs0sTESdR14+IuAyLxcKiRYsYNWoU48aNY9euXSxbtswx6FVEOh91/YiIiIjLUouKiIiIuCwFFREREXFZCioiIiLishRURERExGUpqIiIiIjLUlARERERl6WgIiIiIi5LQUVERERc1v8HrPliRWctB4wAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 梯度裁剪\n",
    "def grad_clipping(model, theta=1):\n",
    "    params = [p for p in model.parameters() if p.requires_grad]\n",
    "    norm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))\n",
    "    if norm > theta:\n",
    "        for param in params:\n",
    "            param.grad[:] *= theta / norm\n",
    "    \n",
    "\n",
    "# 训练\n",
    "from torch.utils.data import DataLoader\n",
    "from torch.optim import SGD, Adam\n",
    "import numpy as np\n",
    "from tqdm import tqdm, trange\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def train_rnn_lm(data_loader, rnn, vocab_size, hidden_size=128, \n",
    "                 epochs=200, learning_rate=1e-3):\n",
    "    # 准备模型、优化器等\n",
    "    rnn_lm = RNNLM(rnn, vocab_size, hidden_size)\n",
    "    optimizer = Adam(rnn_lm.parameters(), lr=learning_rate)\n",
    "    rnn_lm.zero_grad()\n",
    "    rnn_lm.train()\n",
    "\n",
    "    epoch_loss = []\n",
    "    with trange(epochs, desc='epoch', ncols=60) as pbar:\n",
    "        for epoch in pbar:\n",
    "            for step, batch in enumerate(data_loader):\n",
    "                loss = rnn_lm(batch)\n",
    "                pbar.set_description(f'epoch-{epoch}, ' + \\\n",
    "                    f'loss={loss.item():.4f}')\n",
    "                loss.backward()\n",
    "                grad_clipping(rnn_lm)\n",
    "                optimizer.step()\n",
    "                rnn_lm.zero_grad()\n",
    "            epoch_loss.append(loss.item())\n",
    "\n",
    "    epoch_loss = np.array(epoch_loss)\n",
    "    # 打印损失曲线\n",
    "    plt.plot(range(len(epoch_loss)), epoch_loss)\n",
    "    plt.xlabel('training epoch')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "print(sent_tokens.shape)\n",
    "vocab_size = len(dataset.token2id)\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long),\\\n",
    "    batch_size=16, shuffle=True)\n",
    "rnn = RNN(128, 128)\n",
    "train_rnn_lm(data_loader, rnn, vocab_size, hidden_size=128,\\\n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad30e705",
   "metadata": {},
   "source": [
    "接下来仿照循环神经网络实现长短期记忆，同样的接口使得我们可以重用之前的训练代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1995d027",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.3554: 100%|█| 200/200 [16:08<00:00,  4.84s\n"
     ]
    },
    {
     "data": {
      "image/png": "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L35BXV1dh7VTQeUkb775Jvfddx8PP/wwmzZtYtSoUUyfPp3c3FxPN61dli9fzrx581izZg1LliyhtraWiy66iPLycrfzfvrTn5KVleX6eOKJJzzU4rYbNmyYW9tXrlzpOvbzn/+cDz/8kLfeeovly5dz7NgxrrjiCg+2tu3Wr1/vdn9LliwB4Ic//KHrnK72/pWXlzNq1CgWLlzY5PEnnniCZ555hn/+85+sXbuW4OBgpk+fTlVVleucuXPnsmPHDpYsWcJHH33EN998w6233tpZt3BKp7q/iooKNm3axG9/+1s2bdrEu+++y549e7jssssanfv73//e7X392c9+1hnNb5WW3kOAGTNmuLX/9ddfdzvuze8htHyPDe8tKyuLF198EcMwuPLKK93O89b3sTW/H1r6GWqz2bj44oupqanh22+/5eWXX2bx4sU89NBDHddQU9ycffbZ5rx581yPbTabmZSUZC5YsMCDreo4ubm5JmAuX77c9dz5559v3nPPPZ5r1Gl4+OGHzVGjRjV5rKioyPT19TXfeust13O7du0yAXP16tWd1MKOd88995j9+vUz7Xa7aZpd+/0zTdMEzPfee8/12G63mwkJCeaTTz7peq6oqMj09/c3X3/9ddM0TXPnzp0mYK5fv951zqeffmoahmEePXq009reGiffX1PWrVtnAubhw4ddz/Xq1ct8+umnz2zjOkhT93jDDTeYs2fPbvaarvQemmbr3sfZs2ebF1xwgdtzXel9PPn3Q2t+hn7yySemxWIxs7OzXecsWrTIDAsLM6urqzukXaqoNFBTU8PGjRuZNm2a6zmLxcK0adNYvXq1B1vWcYqLiwGIiopye/61114jJiaG4cOH8+CDD1JRUeGJ5rXLvn37SEpKom/fvsydO5eMjAwANm7cSG1trdv7OXjwYNLS0rrs+1lTU8Orr77KTTfd5LYRZ1d+/06Wnp5Odna22/sWHh7OhAkTXO/b6tWriYiIYNy4ca5zpk2bhsViYe3atZ3e5tNVXFyMYRhERES4Pf/4448THR3N6NGjefLJJzu0nN4Zvv76a+Li4hg0aBB33HEH+fn5rmPd7T3Mycnh448/5uabb250rKu8jyf/fmjNz9DVq1czYsQI4uPjXedMnz6dkpISduzY0SHt6tKbEna048ePY7PZ3L7hAPHx8ezevdtDreo4drud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xd/fn5UrV3LgwAFmz55NfHw8ISEhjB8/nqVLl7q95sldG4Zh8PzzzzNnzhyCgoIYMGAA//vf/1zHT+76Wbx4MREREXz++ecMGTKEkJAQZsyYQVZWluuauro67r77biIiIoiOjmb+/PnccMMNXH755ae835UrVzJlyhQCAwNJTU3l7rvvpry83K3tjz76KNdeey3BwcEkJyezcOFCt9fIyMhg9uzZhISEEBYWxlVXXUVOTo7bOR9++CHjx48nICCAmJgY5syZ43a8oqKCm266idDQUNLS0vjXv/51ynaLSMsUVES6ob/97W9MnDiRn/70p2RlZZGVlUVqaqrr+K9+9Ssef/xxdu3axciRIykrK2PWrFl8+eWXbN68mRkzZnDppZeSkZFxyq/zyCOPcNVVV7F161ZmzZrF3LlzKSgoaPb8iooK/vznP/Pvf/+bb775hoyMDB544AHX8T/96U+89tprvPTSS6xatYqSkhLef//9U7bhwIEDzJgxgyuvvJKtW7fy5ptvsnLlSu666y6385588klGjRrF5s2b+dWvfsU999zDkiVLALDb7cyePZuCggKWL1/OkiVLOHjwIFdffbXr+o8//pg5c+Ywa9YsNm/ezJdffsnZZ5/t9jX+8pe/MG7cODZv3sydd97JHXfcwZ49e07ZfhFpQYftwywiXuX8888377nnHrfnnNvWv//++y1eP2zYMPPZZ591Pe7Vq5f59NNPux4D5m9+8xvX47KyMhMwP/30U7evVVhYaJqmab700ksmYO7fv991zcKFC834+HjX4/j4ePPJJ590Pa6rqzPT0tLM2bNnN9vOm2++2bz11lvdnluxYoVpsVjMyspKV9tnzJjhds7VV19tzpw50zRN0/ziiy9Mq9VqZmRkuI7v2LHDBMx169aZpmmaEydONOfOndtsO3r16mVed911rsd2u92Mi4szFy1a1Ow1ItIyVVREeqBx48a5PS4rK+OBBx5gyJAhREREEBISwq5du1qsqIwcOdL1eXBwMGFhYeTm5jZ7flBQEP369XM9TkxMdJ1fXFxMTk6OW5XCarUyduzYU7bhu+++Y/HixYSEhLg+pk+fjt1uJz093XXexIkT3a6bOHEiu3btAmDXrl2kpqa6VZ2GDh1KRESE65wtW7Zw4YUXnrItDb8fhmGQkJBwyu+HiLRMg2lFeqCTZ+888MADLFmyhD//+c/079+fwMBAfvCDH1BTU3PK1/H19XV7bBgGdru9TeebptnG1rsrKyvjtttu4+677250LC0t7bReu6HAwMAWz2nr90NEWqaKikg35efnh81ma9W5q1at4sYbb2TOnDmMGDGChIQEDh06dGYbeJLw8HDi4+NZv3696zmbzcamTZtOed2YMWPYuXMn/fv3b/Th5+fnOm/NmjVu161Zs4YhQ4YAMGTIEDIzM8nMzHQd37lzJ0VFRQwdOhRwVEu+/PLL075PEWkbVVREuqnevXuzdu1aDh06REhICFFRUc2eO2DAAN59910uvfRSDMPgt7/9rUcqAT/72c9YsGAB/fv3Z/DgwTz77LMUFhZiGEaz18yfP59zzjmHu+66i1tuuYXg4GB27tzJkiVL+Pvf/+46b9WqVTzxxBNcfvnlLFmyhLfeeouPP/4YgGnTpjFixAjmzp3LX//6V+rq6rjzzjs5//zzXd1kDz/8MBdeeCH9+vXjmmuuoa6ujk8++YT58+ef2W+KSA+niopIN/XAAw9gtVoZOnQosbGxpxxv8tRTTxEZGcmkSZO49NJLmT59OmPGjOnE1jrMnz+fa6+9luuvv56JEye6xpsEBAQ0e83IkSNZvnw5e/fuZcqUKYwePZqHHnqIpKQkt/Puv/9+NmzYwOjRo3nsscd46qmnmD59OuDoovnggw+IjIzkvPPOY9q0afTt25c333zTdf3UqVN56623+N///sdZZ53FBRdcwLp1687MN0JEXAzzdDuIRUTOELvdzpAhQ7jqqqt49NFH2/06vXv35t577+Xee+/tuMaJSKdQ14+IeI3Dhw/zxRdfcP7551NdXc3f//530tPT+dGPfuTppomIh6jrR0S8hsViYfHixYwfP57Jkyezbds2li5d6hr0KiI9j7p+RERExGupoiIiIiJeS0FFREREvJaCioiIiHgtBRURERHxWgoqIiIi4rUUVERERMRrKaiIiIiI11JQEREREa/1/wFVDGFpQPSt1gAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 长短期记忆\n",
    "def gate_params(input_size, hidden_size):\n",
    "    return (nn.Parameter(normal((input_size, hidden_size))),\n",
    "           nn.Parameter(normal((hidden_size, hidden_size))),\n",
    "           nn.Parameter(torch.zeros(hidden_size)))\n",
    "\n",
    "class LSTM(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 输入门参数\n",
    "        self.W_xi, self.W_hi, self.b_i = gate_params(input_size, hidden_size)\n",
    "        # 遗忘门参数\n",
    "        self.W_xf, self.W_hf, self.b_f = gate_params(input_size, hidden_size)\n",
    "        # 输出门参数\n",
    "        self.W_xo, self.W_ho, self.b_o = gate_params(input_size, hidden_size)\n",
    "        # 候选记忆单元参数\n",
    "        self.W_xc, self.W_hc, self.b_c = gate_params(input_size, hidden_size)\n",
    "        \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),\n",
    "               torch.zeros((batch_size, hidden_size), dtype=torch.float))\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, cell_state = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            I = torch.sigmoid(torch.mm(inputs[step], self.W_xi) \\\n",
    "                + torch.mm(hidden_state, self.W_hi) + self.b_i)\n",
    "            F = torch.sigmoid(torch.mm(inputs[step], self.W_xf) \\\n",
    "                + torch.mm(hidden_state, self.W_hf) + self.b_f)\n",
    "            O = torch.sigmoid(torch.mm(inputs[step], self.W_xo) \\\n",
    "                + torch.mm(hidden_state, self.W_ho) + self.b_o)\n",
    "            C_tilda = torch.tanh(torch.mm(inputs[step], self.W_xc) \\\n",
    "                + torch.mm(hidden_state, self.W_hc) + self.b_c)\n",
    "            cell_state = F * cell_state + I * C_tilda\n",
    "            hidden_state = O * torch.tanh(cell_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state, cell_state)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "lstm = LSTM(128, 128)\n",
    "train_rnn_lm(data_loader, lstm, vocab_size, hidden_size=128, epochs=200, \n",
    "    learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6dafe1d",
   "metadata": {},
   "source": [
    "下面仿照长短期记忆实现门控循环单元。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7c4f3992",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-0, loss=6.9829:   0%|         | 0/200 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.4048: 100%|█| 200/200 [27:53<00:00,  8.37s\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 门控循环单元\n",
    "class GRU(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(GRU, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 更新门参数\n",
    "        self.W_xu, self.W_hu, self.b_u = gate_params(input_size, hidden_size)\n",
    "        # 重置门参数\n",
    "        self.W_xr, self.W_hr, self.b_r = gate_params(input_size, hidden_size)\n",
    "        # 候选隐状态参数\n",
    "        self.W_xh, self.W_hh, self.b_h = gate_params(input_size, hidden_size)\n",
    "        \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            U = torch.sigmoid(torch.mm(inputs[step], self.W_xu)\\\n",
    "                + torch.mm(hidden_state, self.W_hu) + self.b_u)\n",
    "            R = torch.sigmoid(torch.mm(inputs[step], self.W_xr)\\\n",
    "                + torch.mm(hidden_state, self.W_hr) + self.b_r)\n",
    "            H_tilda = torch.tanh(torch.mm(inputs[step], self.W_xh)\\\n",
    "                + torch.mm(R * hidden_state, self.W_hh) + self.b_h)\n",
    "            hidden_state = (1 - U) * hidden_state + U * H_tilda\n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(hiddens, dim=0), (hidden_state,)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "gru = GRU(128, 128)\n",
    "train_rnn_lm(data_loader, gru, vocab_size, hidden_size=128, epochs=200, \n",
    "    learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69537480",
   "metadata": {},
   "source": [
    "下面在循环神经网络的基础上实现多层循环神经网络。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6eb2e0ed",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-0, loss=6.9808:   0%|         | 0/200 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=0.3033: 100%|█| 200/200 [19:30<00:00,  5.85s\n"
     ]
    },
    {
     "data": {
      "image/png": "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r7+eY8eONVpx0riCT+ioxIXWMfRTu+qntBLbz3arBbDbDf781U5eXLi36YoUERE5wVkFld/85jfOzda2b9/Oww8/zOTJk0lLS+Ohhx5q1AKl8dTXUWlXszOtYUB+6cldle2HCnhnZRrPL9xDSlbRSY+LiIg0trMKKmlpac5N2T799FMuu+wynnrqKebMmaOLCnqwwBOCSmwdk2m9LGZnWMktqaSy2s7eE660vCIlx/nn/2442ISVioiIOJxVUPHx8aG0tBSAhQsXMn78eADCwsK0rb0H87aYSQzzw9fbTKeIwDqPqV2inFNcwYuL9nDJ88v530ZHKFl5QlD5bNNBqmz2pi9aRETatLOaTHv++efz0EMPMWrUKNatW8fHH38MwJ49e0hISGjUAqVxffKrkZRUVhPi713n4+GBVlKzS8grqWTJ7mwA3lu1n8v6xbLhgGP+kb+PhZziShbvzmJC75hmq11ERNqes+qovPLKK3h5efG///2P1157jfj4eADmz5/PxIkTG7VAaVwxIb50jqy7mwLHd6c9dKyM5Jphn+2HCnh/zQEqq+3EBPty43ntAfjvel3CQEREmtZZdVSSkpL4+uuvT7r/+eefP+eCxL1qh36W7812Wfnzjx/2ADCqSwRXD0nkjeX7WJKcxcYDxxjcvp1bahURkdbvrIIKgM1mY968eezatQuA3r17c8UVV2CxWOp5pniy2iXKa/flARDq701+aRVlVTYAzu8aTpeoQEZ3i2T5nmyue3M1j13emxuGJ2EymdxWt4iItE5nNfSTkpJCz549uemmm/jss8/47LPPuOGGG+jduzepqamNXaM0o/CaoZ/qmm7KzSM6OIeDAEZ1jgDg1RmDmNQnhiqbwR/n/cQ32480f7EiItLqnVVQuf/+++ncuTMZGRls2rSJTZs2kZ6eTseOHbn//vsbu0ZpRrUdlVqD27dj6gDHHKRu0YFEBTuWNQdavXh1xiCuGuSYPL0uLa95CxURkTbhrIZ+li1bxpo1awgLC3PeFx4eztNPP82oUaMarThpfrVzVGr1Swihe0wQe7OKmT4s0eUxk8lE/8QQPt10kKxCXchQREQa31kFFavVSlHRyTuTFhcX4+PjU8czpKU4cZinY0QAof6O2+/9clidx0cFOTowWUXlTV+ciIi0OWc19HPZZZdx5513snbtWgzDwDAM1qxZw1133cUVV1zR2DVKMwoPPD700y8hpN7jI4McQ0FZReqoiIhI4zuroPLSSy/RuXNnRowYga+vL76+vowcOZIuXbrwwgsvNHKJ0pxC/bwx1yze6Z8QWu/xzo5KYQWG4Xohw1eXpnD166s4pqsxi4jIWTqroZ/Q0FC++OILUlJSnMuTe/bsSZcuXRq1OGl+ZrOJqCBfjhaWMyAptN7jI2uCSqXNTkFZlXOo6K0f9/HMd8mAY0+WKTUTckVERM5Eg4NKfVdFXrJkifPPzz333NlXJG731JV92JtZzMDE0HqP9fW2OPdaySqqINTfh3mbD/GXb3Y5j8ktVkdFRETOToODyubNmxt0nDb9avku7hHNxT2iG3x8VJDVEVQKK0gK8+f3n28HINjXi8LyanKKNX9FRETOToODyokdE5ETRQX5siezmKyicvbnllBaaSPY14vbzu/E8wv3qKMiIiJn7ay30BepVTuhNrOwAj/vEgA6RgY656+ooyIiImdLQUXOWWTw8b1U7DUrfzpFBDj3ZMnRqh8RETlLCipyzqJO2EulqLwacGwWF1HbUdEeKyIicpYUVOScRdd0VLILK5wdlY4RAUQEHB/6MQxDE61FROSMKajIOTveUSn/WUfFMfRTUW2npNJGoFV/3URE5Myc1c60IieqnUx78FgZuTXzUTpGBODv44WftwXQ8I+IiJwdBRU5Z1E1Qz/VdsewT3SwlYCa7kltVyW3REFFRETOnIKKnDN/Hy+XYZ2OEQHOP0fUXOQwu0grf0RE5MwpqEijqB3+AegYEej8c3jNhFp1VERE5GwoqEijqB3+AcceKrUia4Z+ctRRERGRs6CgIo2iduUPuA79qKMiIiLnQkFFGoXL0E/kiXNUajoqp9hGf39OCW/9uI9qm71pCxQRkRZJG1tIo6gd+rGYTSS283feHx5Yuztt3UM/v/10G+vS8mjn78NVgxOavlAREWlR1FGRRlE79JPYzg8fr+N/rWpX/eTUMfRzrKSSDfvzANh9tBAAm93gj/N+4oO1B5q6ZBERaQEUVKRRnNcpnIR2flw5yLUrcnwybQUlFdXc+8Em/rV6PwDL9mRTs/UKKVnFAGw8cIx/rznAX77ehb32QRERabM09CONIibElxWPXnzS/bWTaQvLq/nfxoN8s/0IP+w8yvheMSzaneU8LjW7BDjeWSmrsnEov4zEMP+TXlNERNoOdVSkSYX4eeNldlyM8L2aTkqVzeDN5ftYlnw8qGQcK6W8ysauI0XO+/ZmFSEiIm2bgoo0KbPZRFiAY/hnX03XBODdVWkUllcTFuBDkK8XhgFpOSXOjgrA3sziZq9XREQ8i4KKNLnaCbUAAxJD6RYdiFEz/WRM90i6RDl2st2bVUzy0RM7KgoqIiJtnYKKNLnwmr1UAK7oH8evRnd23r64RxSdIx1BZWlyFqWVNudjCioiIqKgIk0usqajYjLBpf1iubx/HD1igogOtnJht+MdlQU7MgEI8nXM8U7JLMIwtPJHRKQt06ofaXIRNbvWDusQRnSwY7+VefeOAsDX2+LsqBRVVAMwtkcUX287QkmljcMF5cSH+rmhahER8QTqqEiTu3JQPEM7tOM3E7o77/P1tuDrbQGg8wlb7gP0iQ9xXi9ob6ZW/oiItGUKKtLkesQE88ldIxnSIazOx5PC/PG2mJy3e8YG0y06CDi+EZyIiLRNCiridl4WMx3Cj3dVesQEHV8JpCXKIiJtmoKKeITaeSoRgVbCA610ja5dsqyhHxGRtkxBRTxC5yhHR6VnrGPIp2uU4797M4u18kdEpA1TUBGPcGnfOLpFBzJ9WBIAHSL8sZhNFFVUc7ig3HmcQouISNuioCIeoVdcMD/8+kIm940FwOploW98CADztx8BYEtGPv2f+IHXl6W6rU4REWleCirisa4anADA/zYexDAMnluwh8Lyar7cctjNlYmISHNRUBGPdUW/OHy8zOw+WsT/Nh5k+Z5sAFKyi6m22d1cnYiINAcFFfFYIf7ejO8VDcDvP9/uvL+y2s7+3JJTPU1ERFoRBRXxaFcPSQSgyuaYRBsW4LjA4e6jWrYsItIWKKiIRzu/SwSxIY7rAw3rGObssOxRUBERaRMUVMSjWcwm7h/blYhAK7+d0J3uMY79VdRRERFpG9waVGbPns3QoUMJCgoiKiqKqVOnkpyc7M6SxANNH5bEhj+MY0iHMLrXXAMoWRcrFBFpE9waVJYtW8a9997LmjVrWLBgAVVVVYwfP56SEk2UlLrVdlTS80oprax2czUiItLUvNz5zb/77juX23PnziUqKoqNGzcyevRoN1Ulniw80EpEoJWc4gr2ZBYzIDHU3SWJiEgT8qg5KgUFBQCEhYXV+XhFRQWFhYUuX9L29KjpqiQf1fsvItLaeUxQsdvtPPjgg4waNYo+ffrUeczs2bMJCQlxfiUmJjZzleIJutXMU9l6sIA/f7WTm95ZR1ZheT3PEhGRlshkeMhV3u6++27mz5/PihUrSEhIqPOYiooKKioqnLcLCwtJTEykoKCA4ODg5ipV3Oy/6zP47afbXO4blBTKh3eeh9XL4qaqRESkoQoLCwkJCWnQ57dHdFRmzpzJ119/zZIlS04ZUgCsVivBwcEuX9L21E6oBccGcMG+XmxKz+dPX+7Q1ZVFRFoZtwYVwzCYOXMmn3/+OYsXL6Zjx47uLEdaiJ6xwQxu347zu0Twzf3n89L0gZhN8OG6DN5ekebu8kREpBG5dejnnnvu4T//+Q9ffPEF3bt3d94fEhKCn59fvc8/k9aRtG5vLk/lqW93A/DML/pxzRDNXxIR8VRn8vnt1qBiMpnqvP/dd9/llltuqff5CipSyzAMZs/fzZvL92E2wes3DGZ87xh3lyUiInU4k89vt+6jovkE0lhMJhOzJvWgoLSKjzdk8I8f9iioiIi0Ah4xmVakMZhMJh6d1ANwbLGfU1xRzzNERMTTKahIqxIW4OPcEG7Nvlw3VyMiIudKQUVanfM6hQOwOlVBRUSkpVNQkVZnROeaoKKOiohIi6egIq3OeR3DMZlgX3YJmdpaX0SkRVNQkVYnxN+bXrGO5W4nzlMpKK3i5UV7WbE3B7tdK85ERFoCBRVplUbUMU/luQXJ/GPBHm54ey0X/WMpi3Zluqs8ERFpIAUVaZV+Pk/FMAx+2OkIJj4WMwdyS3nwoy0Ulle5rUYREamfgoq0SsM6huFtMXEgt5SfDhXw06FCjhSU4+9jYe3vx9ItOpCiimreX3PA3aWKiMhpKKhIqxTk682kPrEAvL/mAAt2HgVgdNdI2gX4cNeFnQF4Z0Ua5VU25/MW7cqk35++598KMCIiHkFBRVqtG85rD8C8LYf4atsRAC7pFQ3A5f3jiA/1I6e4kk82ZACQWVjOw59spbC8mme/261hIRERD6CgIq3W0A7t6B4dRHmVnbScEixmExf3iALA22LmztGdAHhlSQqLd2fyyCdbyS91hJPC8mrmrtzvrtJFRKSGgoq0WiaTiRtGtHfeHtK+He0CfJy3rx2aSHyoH5mFFfxy7gZ+3JuD1cvMg+O6AvDWj/vUVRERcTMFFWnVpg2MJ8DHAhwf9qnl623h83tHcufoTs5j/nBZL+67uCtdogLVVRER8QAmwzBa7M5XhYWFhISEUFBQQHBwsLvLEQ/18fp0vvvpKM9fO4BQf586jykoreJQfhm94hx/j77cepj7P9yMn7eFL2eOomt0UHOWLCLSqp3J57eCikgd7HaDG99Zy8qUXDpHBvDlzPMJsHq5uywRkVbhTD6/NfQjUgez2cSL1w0kJtiX1OwSZn223d0liYi0SQoqIqcQEWhlzoyBeJlNfLn1MHsyi9xdkohIm6OgInIag9uHMbRDGACb04+5uRoRkbZHQUWkHv0SQwDYerDAzZWIiLQ9Cioi9egXHwrAtoP5bq1DRKQtUlARqUe/BEdHZfeRIpfrAomISNNTUBGpR0I7P8ICfKi2G+w6UljnMYXlVeQWVzRzZSIirZ82hhCph8lkol9CCEuTs9l2sICBSe0AMAyDj9Zn8OnGg2zOyMfbYuLr+y6gS1SgmysWEWk91FERaYB+CaEAbD1hnsq8LYeY9dl2Nhw4hs1uUF5lZ+6qNPcUKCLSSimoiDRA/5p5KttqVv4cKSjjsS92AHDziPa8cO0AAD7fdIgiXchQRKTRKKiINEBtRyU1u5j80kp++79tFJVXMyAxlD9e1ospA+LoEhVISaWNzzYdcnlueZVNk3BFRM6SgopIA0QGWYkL8cUwYPhTi/hxbw6+3mb+cU1/vCxmTCYTN57XHoB/rzlA7SW0yqtsjH9+OZe9vIIqm92dpyAi0iIpqIg00JCaHWorqu2EB/jw7C/60zny+MTZaYPi8fexkJJVzOrUXAA2pR8jPa+UlKxitmbkO49twdcCFRFpVgoqIg30f5f25Mkpvfn8npGs/79xXN4/zuXxYF9vpgyIB+CrbYcBWLMvz/n48j3ZAHy7/Qjd/jCfb7YdaabKRURaLgUVkQaKDvblxhEdGJjUDrPZVOcxE/vEALBoVxaGYbCmprMCsGxvDgCvLk2hymYw/ycFFRGR+iioiDSi4R3D8PexkFVUwYYDx9hywnDPtoP5rN2Xy0+HHJvG7c0sdlOVIiIth4KKSCPy9bZwfpcIAP7+fTKVNjsxwb50iw7EMGDWZ9udx+7LKdYEWxGReiioiDSysT2jAFib5pifcl6nMEZ3jQRgX06J87gqm8GB3FKX5+48XMicJSmUVlY3U7UiIp5NQUWkkV3UI8rl9ojO4VzQLdJ5u52/Nz1jgwHYm1nkcuysz7fz7PfJPF6zmZyISFunoCLSyKKCfJ072QKc1ymc4R3DsHo5/rld0T+OXrVBJev4PJXsogrnEuZPNh5k/nZNthURUVARaQIX94gGIDbEl6Qwf3y9LUwZEEeAj4UbzmtPt2jH/it7Tuio1C5frl1QNOvz7WQWljdv4SIiHkZBRaQJXDM0gb7xIdw9pjMmkyN5PH1lPzY9dgldo4PoFh0EuK78WZKcBcAdozvRJz6Y/NIqnvkuufmLFxHxIAoqIk0gNsSPr+47n5tGdHDeZzabsHpZAOgS5eio7Mspptpmp9pmd3ZUxveK4c9T+gCOjePySyubt3gREQ+ioCLiBvGhfvj7WKiyGezPLWVLRj6F5dWE+nszIDGUgYmh9IwNprLazqc/u8ihiEhboqAi4gZms4muNV2VvZlFzmGfC7tFYjGbMJlMzBieBMAHaw/o2kAi0mYpqIi4SZcoxzyVNftymf/TUQDGdD++jHnKgDj8fSzsyy5x7skiItLWKKiIuEntyp/3Vh9gX3YJ/j4W58ZwAEG+3kwZ4Ljw4Qdr091So4iIuymoiLhJj5q9VAD6JYTw79uGEx5odTnmmiGJACzZnYXdruEfEWl7vNxdgEhbdX6XCH4zoTsdIwKY2Dumzisy940PwdfbTHFFNftyip3DRSIibYU6KiJuYjGbuPeiLkzuG1tnSAHwspjpG+/Y5XZrRgEAu44UMnv+LrK0GZyItAEKKiIerl9CKABbD+YD8OTXO3lj2T6ue3ONwoqItHoa+hHxcP0TQwHYerCAwvIq1tWsANqXU8J1b67hkt7R7MsuYVTncG4Z1dGNlYqIND4FFREPV3uBw12HC1m8K4tqu0F8qB/gCCtvLNsHwOLdWUwdGE+ov0+dr3OspJLvdxzlh52ZVFbbefWGQQT7ejfPSYiInCUFFREPlxTmT6i/N/mlVby2NBWASX1iuHlkB/7xQzLBft4s2pXFofwylu3JZsqA+JNeo6Csiktf+pHDBceHihbuzOTKQQnNdh4iImdDc1REPJzJZHLOU0muudryxT2jSAzz54XrBvLnKX24oma/lSW7HTvc2u0GB4+VOl/jv+szOFxQTlSQ1TmUtO1gQfOdhIjIWVJQEWkBBtQM/wAEWb0Y2iHM5fGxPaIAWLonm2qbnb99v5vz/7aEN5enUm2zM3fVfgAeuqQbt4xsD8BPhxRURMTzaehHpAWo7agAjO4WibfF9f8xBia1cw4Pfbb5EG//mAbAM98lU1RezaH8Mtr5ezN1YDwHj5UBsONwIdU2O14W/f+KiHgu/YYSaQH6JR7vqFxU0z05kcVsYkw3x/b7f/j8J6rtBt4WE9V2g5cXpwBw/fAkfL0tdIoIIMDHQlmVjdTskuY5ARGRs+TWoLJ8+XIuv/xy4uLiMJlMzJs3z53liHisqCBfhnUIIzLI6hzm+bmLe0YDUGmzYzbB+7cNJyrIsSW/l9nEjed1ABxXbu5Ts4nctpq9WUREPJVbg0pJSQn9+/dnzpw57ixDpEX44I7h/Pjbi2gXUPfy4wu7RmKp2eH22qGJDO8UznPXDMDqZWb6sCRiQnydx9budrtd81RExMO5dY7KpEmTmDRpUoOPr6iooKKiwnm7sLCwKcoS8UjeFjPellM/HuLvzY3ntWdtWh6/vqQbAOd3jWDr4+Oxern+P0nfBAUVEWkZWtRk2tmzZ/PEE0+4uwwRj/WnK3qfdJ9vHemmdnLuzsOFVNnsJ03ObQi73aCwvOqUG8yJiDSGFjWZdtasWRQUFDi/MjIy3F2SSIvUPsyfIF8vKqrtrEzJ4eP16eyp2aOlof723W4GPbmAhTszm6hKEZEW1lGxWq1YrVZ3lyHS4pnNJvrGh7AqNZdb3l0PQKDVi7m3DmVgUjv+tXo/Px0q5PEretW5zX5JRTXvrzmA3YCnvt3FmO6RWuYsIk2iRQUVEWk8wzuGsyo1F4CIQCs5xRXc9M46ukYHsTUjH4Cu0YHcdWHnk577zfYjlFTaAMf1hv638SDXDUtqttpFpO3Q/wKJtFG/urATr98wmB9/exE//vYizu8SQWmlzRlSABacYljnkw2OYdcuUYEAvLBwL+VVtiavWUTaHrcGleLiYrZs2cKWLVsASEtLY8uWLaSnp7uzLJE2wdfbwsQ+MSSG+ePnY+Gtm4dw9eAEJveN4X93jQBgU/oxsosqXJ6Xml3M+v3HMJvg3VuGEhfiy9HCct5fc8AdpyEirZxbh342bNjARRdd5Lz90EMPAXDzzTczd+5cN1Ul0jb5elt49ur+ztt940PYfqiAxbszGdM9ipvfWYfFbCLAx/Fr46Lujgsj3j+2K7/7bDvvrd7PL0d1xGw28Yd529maUcB7vxxG2Cn2fRERaQi3BpUxY8ZgGIY7SxCRU7ikVzTbDxXww45MFu7KYvdR11VBVw9JBGDKgHj++u0uMvLKWJmaQ6ifD++vcXRFX1uawv9d2qvZaxeR1kNzVESkTpf0cmzJvzg5iwU7M/G2mPjDpT2Z2DuGqwcnMLanYyt/Px8LVw6MB+DDdem8vjzV+Rr/Wn2ArMLy5i9eRFoNBRURqVOPmCAS2vlR2/S8e0wXbr+gE6/fOJhnr+7vsklc7YqfH3ZkMn/7EQA6RgRQUW3n1aWpJ722iEhDKaiISJ1MJhPje8UAjtU991508jLlWj1jg+mfGEq13cBuwNgeUfxlah8A/rM2nUP5Zc1Ss4i0PgoqInJKMy/uwp2jO/HPm4Zg9TrNhYaA64clOv9895jOjOwcznmdwqi02bnzXxsoLK9q6nJFpBVSUBGRUwoL8OH3k3vSMSKg3mMv7x/HiE7hXDc0kSEdwjCZTDw1rS/hAT7sOFzIL99dT2lldTNULSKticlowctuCgsLCQkJoaCggODgYHeXIyJ12HG4gOveXENReTUXdI3grZvr786ISOt2Jp/f6qiISJPqHRfC3FuH4udt4ce9OTzw4RbKKm0s2Z3FN9uOUFF96h1tc4orWLE3R9sYiLRh6qiISLNYsTeHX85dT6XNjrfFRJXN8aunc2QAD4/vzp7MIlam5NA/IZRfX9KN/bkl3PruerKKKphz/SAu7Rfr8nqrU3MpKKtkYp/Yur6diHiwM/n8VlARkWbz/Y6j3PPBJmx2g+hgKza7QU5x5UnHJYb5caykiuIKx5yWPvHBfDXzfEwmEwCH88sY8+xSKm12Fj18IZ0jA5v1PETk3JzJ57euniwizWZC7xi+vu98yqts9E8Ipaiimn/8kMy324/SOy6YC7pG8O7K/WTkOZYzD+3Qju2HCvjpUCFr9uUxonM4AHOWpFBpswOwLDlbQUWkFVNHRUQ8SlF5FS8t2othwCMTuvOXb3by/pp0xvaI4u1bhnLwWCkX/X2pc+hoTPdI5t46zM1Vi8iZUEdFRFqsIF9vl+sD3XZ+Jz5Ym86i3Vks3JnJ/J+OUmUz6BDuz/7cUtbsy6Wi2kZ2UQVPfr2TxHb+XNwziqEdwlx2zxWRlkn/ikXEo3WMCGBcT8d1h27/1wY+3XQQgGev7k9UkJXyKjsb9h/jqW938f2OTN5akcb1/1zLmGeX8sWWQ9jtx5vGGXmlXP36Kj7deNAt5yIiZ05BRUQ83qMTe3BB1wgS2vnhZTYxZUAcQzuEcUHXSAD++eM+vt1+FJPJsfFcO39vDuWX8cBHW7jmjdXOSbnPfJ/M+v3HmD1/N1U1c1xW7M3h5UV7qa65LSKeRUM/IuLxukQF8u/bhgNgGIZz9c/obhF8uukgS5OzAbi0bywvTx9IWaWNt1fs47WlqWw4cIxnv9vNjSPa8/W2w4Bjf5alydkM7xTG3R9spKi8msggq/PiiiLiOdRREZEWpTakAJzfJcL5Z7MJHhzXFQA/HwszL+7KGzcOAeBfaw7w8H+3YhjgbXE8/78bMvj36gMUlTu6LW+vSNPGctLqfbHlELe8u46C0pZz7S0FFRFpscIDrfSJd6wYmDIgni5RQS6Pn981gl8MTsAwYOvBAgD+fnV/ABbvzuLN5fucx+7NKmb53hyKK6p5YeEeVuzNaVANeSWVZBaWN8bpiDS515ftY2lyNkv3ZLm7lAZTUBGRFu23E3owuW8Mj07sUefjf7i0JxGBPgCM6xnNlAHxDEwKxWY3KCirokO4PzePaA/AnMUpXP/PNbywcC83vL2WlxbtdZmMm1VYzpp9uVRWO+azVNnsTJ2zknHPLSO7qAIAu93ghx1HT3u16MP5ZVz7xmr+uyGjUX4GIg1hGAYZeaUALSpca46KiLRoo7tFMrpb5CkfD/X34eXpg3h7RRp/vKwnANcMSWRzej4A94zpwnmdwvn3mgOs258HgK+3mfIqO88t2MPX2w4TaPUir6SS/bmOX/K/Gt2JWZN7sjo1l/SaX/zfbDvMLaM68taKfTz17W6uHBjPc9cOAKDaZqfabuDr7bgY49sr0liblse6/XmE+nkzvndMU/xoRFwcKz2+2/PRggo3V9Nw6qiISKs3onM4b908hPbhAQBc1i+W+FA/esUGM21QPEnh/kyoCQtxIb58c/8FPH1lX7wtJvZkFrMpPd8ZUgA+Wp9BeZWNb7Ydcd735dbD2O0G769JB2D+T0cpq7RhGAY3vL2WUU8v5nB+GdU2O19scUzqNQx44KMtbK8ZlhJpSrWhGiCzSB0VERGPFeTrzdLfjAFwbgr3pyt60ys2mKuHJBIT4kvnyEBGdYlg15FCDMDP20K/hBAmv/gjhwvK+WbbEb7fedT5mpvS8/l4Q4bzw6CsysaS5CwiAq2s2efo1Ly6NIVxPaPJKa6gnb83feJD+HFvDne9v5HFj1yI1ctCWk4J763az+0XdCShnX+Dzyk1uxizyUTHiIDG+SFJq3NiUMnS0I+IiGf7+a610cG+3De2q8t9iWH+JIa5hoWrhyTy4qK9/PXbXeSXVhER6EPnyEDWpuXxpy93AI5QU1Zl4+tth7GYj3+fj9dnkJpVAjj2e3lkQncueW4Zh/LLmLf5ENcMSeSRT7ay8cAxVqbk8Pm9owi0nv7X9MqUHF5dmsLKlFz8fSwseWQM0cG+Z/1zkdYr44SgcrQFBRUN/YiInIGrhyRgMjlW+wBM7BPDtIHxAFTUTLJ9cmofABbtyuK7nxzDQ50iAqiyGazelwvAtIHxBPt6c9v5HQF4Y/k+Fu3KYuOBY4BjFdJvPtl62iXT6/fnccPba1mZ4njN0kob8zYfqvNYu91g7b5cNh7IO6fzl5Yr/YThy8zCihazHF9BRUTkDCS083fZv+XSvnFM6hPr3J9lUFIoVw2Kp324PxXVdqpsBoOSQpl9ZV/nczpGBDAgMRSA6cOSCPL1Yl92CQ/9dwsAY3tE4W0xMf+nozzzffIpP1DeWJaKYcDFPaKce8h8uumgy/GGYfDGslRG/W0x1765hmveWENqdnFj/kikhThx6Key2k5BWcvYS0VBRUTkDF031LGDbWSQlWEdwwjx92Zin1gAbhnVEZPJxKV9Y53H3zSiA8M7hTOyczgAVw2Kd25cF+TrzY3nOZZHF5ZXE2T14u9X9+eJKxxdmdeWpnLPB5soqVmtUSstp4RFux17YfzfpT25dVRHfLzM7MksZsfhQudxS/dkM3v+bo4UOFr9Nrvh3Mm3OSzfk83Yfyxl/vYj9R8sTerEoAItZ/hHQUVE5AxN6hPDn6f05vUbBmExOwLH7Cv7Mu/eUVzRPw6AKwbEYTZBVJCVSX0dK4pemj6Qp6b15c7RnV1erzZkANwxuhPtAny4fngSs2tWHs3/6Si/eH21y/8Bv7syzdlN6RwZSIifN5f0cly8sfbCjQAf1KxCunpwAo+M7wbAj3sdQaWs0sZzC/aw++jxYNMQezOL+GRDBjb76YcOUrKKuPeDTaRml/DB2vQz+h4tVUFplUcOqVRW2zlSUAZARKAVcAz/tAQKKiIiZ8hsNnHTiA4Mbh/mvC/Q6uUczgHoERPMJ3eN4L+/GoHVy7F/SkSgleuHJzlDSa3IICt/mdqHa4YkcPsFHZ33Tx+WxEd3nkdEoA+7jhRy7webqLLZKSit4pMNjjBSO8cF4BeDEgD4csthqmx2jhaUs3h3JgC/urATY2uuQr1mXy4V1TZeX5bKS4v28qt/b3RuYlefgrIqZry1lt/8bxuvL0s95XH5pZXc9t4Gimo6QVsy8p3B5qGPtzD++WXsOHxmy7LLq2ykZhezbE82+3NKzui5zeHDden0//MPzNtS9zwhdzqcX4bdcEz07hXn2M05s0AdFRGRNm1w+zA6NHC58DVDEnnmF/3x93Fd5TO4fRhzbx2Gv4+FFSk53PDWWia/9CNlVTZ6xAQ5h5MALugaQUSgldySSv754z4+Xp+B3YBhHcPoEhVEj5ggIgKtlFfZWbsvj4/WO7ocB3JLeX/NgQbV+cx3u8mq2YX3hYV72Hn45G5MRbWNu9/fxIHcUuJD/fD3sVBcUU1qdjFZReV8tvkQezKLueq1VS570ZzOjsMFDHpyAWP/sYyb31nHpS/96LKKxd0Mw+CfPzouyfDDjsyzeo3FuzO5be56jp4QILYfLGiU86wd9kkK8ycmuLajoqAiIiKNoE98CK9cPxCzCdam5XEov4xgXy8eu7yXy0UavSxm7h7jGFZ65rtkZ8fj+pqrQptMJkZ3dUwE/us3u8gsrKBm5IqXFu+td3Ll+v15ziGcPvHBVNkMHvrvFiqqbc5j7HaD33yyjdX7cgnwsfDWzUPoGx8CwJb0fFbVrFAymaC8ys69/9nEkuT6rzvz8qIUSitt+HlbCPX3pqTSxqOfbjunYRbDMOodvmqo7YcK2Jft6PLsqCO81ae8ysZv/7edRbuznO9b8tEipr66kqlzVp7zRQRrg0pimD8xNcvXW8qmbwoqIiItwMU9onnxuoFMGRDHK9cPZN3/jWNk54iTjrvt/I7OFUBlVTZC/b2Z2Of4Fv3n1wSV5MwiwDEnpmtUIPmlVby8aO8pv7/NbvD7z7YDcO2QRObeOoywAB92Hy3i7RVpzuP+/kMyX249jJfZxOs3DqZnbDADk9oBsDnjGD/WXOzx9vM7Opd1/2vV/tOee2p2sXNzvS9njmLePaPw9TazKjWXd1buZ+HOTN5Ylsq+M1jNVFxRzbVvrmHsP5ZyOL+swc87lc9PWBaenld62ms91eWjdenkFFc4X6u8ysZ7q/djsxvkllTy0uK63xu73WBz+rF6uy4ndlSiaoJKS9lGX0FFRKSFuLx/HC9eN5DL+sU5rxtUlwfHdePhS7phMsEtIzu4HHvi0mqTCW48rz2/n+y4BtJbK9L423e76+wy/Lg3m71ZxYT4eTNrcg8iAq38bpLjQpAfrEnHZjfYn1PCazXdgL9d1Y8LujquwTQwKRSAzen5rEhxTOS9sFsU913cBYBle7JPOwzx1o/7MAwY1zOKrtFBdIgI4LcTHN/7ya93cvu/NjB7/m4mvLCcp77dRVEdIWHD/jxGPb2YP325g5KKau77zybWpeWxP7eUBz/eckadlY0H8lyCSLXNzldbDzt/pkCdQ2Kn4pgv5Bg2Mpsc84A+3XTQZU+c91btdwaxkopqliZn8ZevdzLqb4uZ9uoqJr3442mDWu0eKklhfs4NAbNaSEdFO9OKiLRC943tyk0jOxDs6/prPirYlx4xQew+WsTF3aNIaOdPfKgfMy/qwitLUnhtaSo7Dhfyf5N70j0myPm82is9TxsYT6i/42rUV/SP46/f7OJQfhnL92azLDkbw4CLukdy1eAE53MH1kwy3n3U0cXx8TIzpEM7fL0tDGnfjg0HjvH55kPcdeHx1VBHCsrYkp6Pr7eFTzc6PrB/dcLjt4zswMJdmaxKzSUxzI+YYF/W7z/Gm8v3kZpVzNu3DHU571eWpHAov4y5q/bz2aaDFJZXY/Uy42U2sS4tjzlLUrj/ZzsT1+XLrYe5/8PNjOgUzn/uGI7JZGJFSg45xZWEBfjQPyGEJcnZ7DhcyPCOYTz59S7Kqmz8dWofzObjw3SF5VXc/f5Gx3sS5MvRwnJign2ZOjCe15el8uevdlJRbadrVCDx7fxYmpzNzP9sxs/HwtaMfKp/FqyKK6q554NNzLt3VJ0h1tlRCfcnMrBm6OcU4dAwDIoqqgn29a7359Ec1FEREWmlQvy8Xeaw1Prl+R2JC/F1fjCbTCYemdCdF68bgNXLzPI92Ux4YTm3vruOQ/ll5JVUsmCnY4LoNUMSna/j623hykGO4Zt/Lt/nDDO3nd/J5ftFBfsSH+rnvD2sQ5jzw/QXNYHmkw0ZzvkmNrvB9DfXcPcHm7h17noqbXYGt2/H0A7HV1mZzSbm3jqMNbPGsvw3F/HJXSP5501DAFiSnOUcRgFH52D5HkcnJzzAh8Jyx0qk568dwF+mOfareXHRXrZm5J/0s3ptaSp3/msDheWOZcevLkkBYPW+XOcuw59sdKzAurxfLP1rQtmOwwXsPFLIOyvT+HBdunPPm1rzNh9iZUouK1NyncNGd13YiRnDkzCZju9yfNOI9vzh0l54mU3sPFLIxgPHqLYbxIf68YvBCbx+w2B+/O1FhNcMwz3x1c6TzqG8yuYy9BNdM5k2u6iCapvraq/MwnKufn01g59cwJLd9c8dag7qqIiItDHXDEl0CRy1pgyIp3tMEC8t2st3Px1lSXI2N769lsv6xlJlM+gbH+Jc2lpr+rAk3l25n1Wpjg/tHjFBjOoSftJrD0gK5VDNXJDaeTIAl/aL5U9f7SA1u4QtGfkMTGrHol2Z7M8txdfbTGyIH5XVducw04l8vMzEhBy/rtElvaLpEx/MT4cKWbwri2uGOs7xi82HsRuOXYPfunkory5JoW9CCJNrNuVbvDubr7Ye5pUlKc6wA44P8r//kIzNbjD7211M6hPr7AoBvLhwL8Xl1c6VS78YnOjcRG3n4UK+rBkOAnh9Wapznxs4Pqflkl7R5JdWEmj14rphSfh6WxjVOYIVKTkEWr2YNiiBQKsXz17djzWpeQxu344RncNPugbVC9cN4KZ31vHhunR6xQZx44gOAOQWV3D7vzZQXFFNqL83Ce388baYsZhNzvkvtUNBG/bncdf7m5wh78lvdnJB1wi8LO7taSioiIiIU4+YYF6dMZh92cXc8NZa9mWX8NJiRxfhmiEJJx3fLTrIOXwD8MuanXl/bmBiqPMD/cR5MkG+3kzqE8vnmw/x9oo0Xrm+Hf9a7VgqffPIDsya1POM6r+kZww/HSrkh52ZzqBSuwHelYMSCAvw4Q+X9XJ5zgNju/LV1sMs3JXJvuxiOkUGAo6uR+3clQ/XZTjD2KV9Y1mwM5O1aXlsO+jYC+bO0Z3omxBCeL5jWGxvVrHLKqqNB46xYX8eQzqEsT+nhM3p+ZhN8NdpfYgKcr2I5J2jO7EqNYdfnt/ReVHKaQMTmDbw5J9/rQu6RvLwJd34+w97ePzLHUQGWamyGTz7fTLpeaWE+Hnz5o1DnJ2syEArRwvLySwsJzrYl/IqG7f/awP5pVX0iAkis7Ccfdkl/G/jQa6rWTXmLhr6ERGRk3SKDOTdW4cRVPNBafUyc8WA+DqPnV7zQRYe4MMVA+LqPKZ22CYi0EqvWNeuzC0jO2A2wdfbjvCPH5JZkZKDuWai75ka39vRtfhxbzalldXsPFzI7qNF+FjMXNYvts7ndIkKZGyPKAwD5womwzD4X82QTlJN9+JAbikWs4lZk3twdU1oK6uy0S8hhEfGdwcgNsSXdv7e2OwGRwrKCbR6MbXmZ1I7YbZ2Q7jzu0aeFFIARneL5KcnJvDrcfXPmTnRvRd14bqhidgNuOv9Tdz34WbS80pJDPPj07tHMqzj8aGz2uGf2j1bFuzMJL+0ivhQPz67ZyQzL3Z87+cX7qGs0nbyN2tGCioiIlKn7jFBvHHjYEL9vbllVAdC/OqeXDl1YDz/N7knb9w4+JSrkfonhvLidQP4502DXSaV1j5WO1/m5Zruzbie0SS08z/pderTIyaIhHZ+VFTbWb4nh3dWOoLH2J5RzknAdbn9Ase8mv9tPEheSSXbDxWQnFmE1cvMR3ee55xjc2nfWBLa+XPPRV3w9TYTaPXipesGOncbNplM9I4Lcb7u+F7R3De2KyYTLNyVyYfr0p2reaYNrDvUAfj7eNXZmTodk8nEX6b24aLujtVW7fy9eXBcV76eeQFdogJdjo127qVyfEm0o6Z4/H28uOG8JOJD/cgsrGBuPcvHm5qGfkRE5JRGdolg8x8vOe2HpsVs4o7RnU75eK0pp+jIANx3cVdWp+ayNi0PcHRZzobJZGJ8rxjeWZnGo59ucw6/1Dd8cV6nMOf8lt/+b6szeEzoHUNcqB+v3zCYuav283DN9ZLiQ/2Y/8BovMymk+aL9IoLZkWKY7+YywfE0TkykGkD4vls8yFm1exF4+dtYXyvGBqbl8XMmzcNYf3+PAYkhp6003Gt2qByOL+MnOIKltVMNp5as7eN1cvCQ5d04+FPtrIiJZu7Lux0xsGpsSioiIjIaTXHB5TFbOLF6wbyi9dXkRTmz4jOJ0/IbajxvaN5Z2UaBWVVWMwmnriiNxd2izztc0wmEw+M7cYd/9rAwl3HV7vUDvH0TQjhH9f0d3lOx1NcHqF3zYTjdv7ezvk4f/tFP3rFBfPCwr0UV1QzqU8MAdam+Qj2tpjr3AzwRN1qlp7/a9V+8kursNkN+iWEuHRepg6MJ9jPm7E9otwWUgBMhide5rGBCgsLCQkJoaCggODg4PqfICIiHs0wjHP+UKy22bnk+eXklVQy5/pBLquM6rM5/RivLU3lh52ZdI8O4tsHLnBeIbuhyqtsPPbFT4zpHuVcWVQrq7CcxbuzmNwv1q37lFTZ7Nz8zjrnBGGAxy/vxa2jOp7mWY3nTD6/FVRERKTVKa+yYbMbZ921yCoqx8/bQpCHbHrWFApKq5j26kr25ZRgMZtY+/uxRARam+V7n8nntybTiohIq+PrbTmnoZWoIN9WHVIAQvy9eeeWoXSPDuLWkR2aLaScKc1RERERaaM6RATw/a9Hu7uM01JHRURERDyWgoqIiIh4LAUVERER8VgKKiIiIuKxFFRERETEYymoiIiIiMdSUBERERGPpaAiIiIiHktBRURERDyWgoqIiIh4LI8IKnPmzKFDhw74+voyfPhw1q1b5+6SRERExAO4Pah8/PHHPPTQQzz++ONs2rSJ/v37M2HCBLKystxdmoiIiLiZ24PKc889xx133MGtt95Kr169eP311/H39+edd95xd2kiIiLiZm4NKpWVlWzcuJFx48Y57zObzYwbN47Vq1efdHxFRQWFhYUuXyIiItJ6ebnzm+fk5GCz2YiOjna5Pzo6mt27d590/OzZs3niiSdOul+BRUREpOWo/dw2DKPeY90aVM7UrFmzeOihh5y3Dx06RK9evUhMTHRjVSIiInI2ioqKCAkJOe0xbg0qERERWCwWMjMzXe7PzMwkJibmpOOtVitWq9V5OzAwkIyMDIKCgjCZTI1aW2FhIYmJiWRkZBAcHNyor+0JWvv5gc6xNWjt5wc6x9agtZ8fNP45GoZBUVERcXFx9R7r1qDi4+PD4MGDWbRoEVOnTgXAbrezaNEiZs6cWe/zzWYzCQkJTVpjcHBwq/2LB63//EDn2Bq09vMDnWNr0NrPDxr3HOvrpNRy+9DPQw89xM0338yQIUMYNmwYL7zwAiUlJdx6663uLk1ERETczO1B5dprryU7O5vHHnuMo0ePMmDAAL777ruTJtiKiIhI2+P2oAIwc+bMBg31NCer1crjjz/uMiemNWnt5wc6x9agtZ8f6Bxbg9Z+fuDeczQZDVkbJCIiIuIGbt+ZVkRERORUFFRERETEYymoiIiIiMdSUBERERGPpaBShzlz5tChQwd8fX0ZPnw469atc3dJZ2327NkMHTqUoKAgoqKimDp1KsnJyS7HjBkzBpPJ5PJ11113uaniM/OnP/3ppNp79OjhfLy8vJx7772X8PBwAgMDueqqq07aCdnTdejQ4aRzNJlM3HvvvUDLfP+WL1/O5ZdfTlxcHCaTiXnz5rk8bhgGjz32GLGxsfj5+TFu3Dj27t3rckxeXh4zZswgODiY0NBQbrvtNoqLi5vxLE7tdOdXVVXFo48+St++fQkICCAuLo6bbrqJw4cPu7xGXe/7008/3cxncmr1vYe33HLLSfVPnDjR5RhPfg+h/nOs69+lyWTi2WefdR7jye9jQz4fGvI7ND09nUsvvRR/f3+ioqL4zW9+Q3V1daPVqaDyMx9//DEPPfQQjz/+OJs2baJ///5MmDCBrKwsd5d2VpYtW8a9997LmjVrWLBgAVVVVYwfP56SkhKX4+644w6OHDni/HrmmWfcVPGZ6927t0vtK1ascD7261//mq+++opPPvmEZcuWcfjwYa688ko3Vnvm1q9f73J+CxYsAODqq692HtPS3r+SkhL69+/PnDlz6nz8mWee4aWXXuL1119n7dq1BAQEMGHCBMrLy53HzJgxgx07drBgwQK+/vprli9fzp133tlcp3Bapzu/0tJSNm3axB//+Ec2bdrEZ599RnJyMldcccVJx/75z392eV/vu+++5ii/Qep7DwEmTpzoUv+HH37o8rgnv4dQ/zmeeG5HjhzhnXfewWQycdVVV7kc56nvY0M+H+r7HWqz2bj00kuprKxk1apVvPfee8ydO5fHHnus8Qo1xMWwYcOMe++913nbZrMZcXFxxuzZs91YVePJysoyAGPZsmXO+y688ELjgQcecF9R5+Dxxx83+vfvX+dj+fn5hre3t/HJJ58479u1a5cBGKtXr26mChvfAw88YHTu3Nmw2+2GYbTs988wDAMwPv/8c+dtu91uxMTEGM8++6zzvvz8fMNqtRoffvihYRiGsXPnTgMw1q9f7zxm/vz5hslkMg4dOtRstTfEz8+vLuvWrTMA48CBA8772rdvbzz//PNNW1wjqescb775ZmPKlCmnfE5Leg8No2Hv45QpU4yLL77Y5b6W9D7+/POhIb9Dv/32W8NsNhtHjx51HvPaa68ZwcHBRkVFRaPUpY7KCSorK9m4cSPjxo1z3mc2mxk3bhyrV692Y2WNp6CgAICwsDCX+z/44AMiIiLo06cPs2bNorS01B3lnZW9e/cSFxdHp06dmDFjBunp6QBs3LiRqqoql/ezR48eJCUltdj3s7Kykvfff59f/vKXLhfibMnv38+lpaVx9OhRl/ctJCSE4cOHO9+31atXExoaypAhQ5zHjBs3DrPZzNq1a5u95nNVUFCAyWQiNDTU5f6nn36a8PBwBg4cyLPPPtuo7fTmsHTpUqKioujevTt33303ubm5zsda23uYmZnJN998w2233XbSYy3lffz550NDfoeuXr2avn37uuwmP2HCBAoLC9mxY0ej1OURO9N6ipycHGw220nb90dHR7N79243VdV47HY7Dz74IKNGjaJPnz7O+6+//nrat29PXFwc27Zt49FHHyU5OZnPPvvMjdU2zPDhw5k7dy7du3fnyJEjPPHEE1xwwQX89NNPHD16FB8fn5N++UdHR3P06FH3FHyO5s2bR35+Prfccovzvpb8/tWl9r2p699h7WNHjx4lKirK5XEvLy/CwsJa3HtbXl7Oo48+yvTp010u9nb//fczaNAgwsLCWLVqFbNmzeLIkSM899xzbqy24SZOnMiVV15Jx44dSU1N5fe//z2TJk1i9erVWCyWVvUeArz33nsEBQWdNLTcUt7Huj4fGvI79OjRo3X+W619rDEoqLQh9957Lz/99JPLHA7AZUy4b9++xMbGMnbsWFJTU+ncuXNzl3lGJk2a5Pxzv379GD58OO3bt+e///0vfn5+bqysabz99ttMmjTJ5dLoLfn9a+uqqqq45pprMAyD1157zeWxhx56yPnnfv364ePjw69+9Stmz57dIrZqv+6665x/7tu3L/369aNz584sXbqUsWPHurGypvHOO+8wY8YMfH19Xe5vKe/jqT4fPIGGfk4QERGBxWI5aUZzZmYmMTExbqqqccycOZOvv/6aJUuWkJCQcNpjhw8fDkBKSkpzlNaoQkND6datGykpKcTExFBZWUl+fr7LMS31/Txw4AALFy7k9ttvP+1xLfn9A5zvzen+HcbExJw0wb26upq8vLwW897WhpQDBw6wYMECl25KXYYPH051dTX79+9vngIbWadOnYiIiHD+vWwN72GtH3/8keTk5Hr/bYJnvo+n+nxoyO/QmJiYOv+t1j7WGBRUTuDj48PgwYNZtGiR8z673c6iRYsYMWKEGys7e4ZhMHPmTD7//HMWL15Mx44d633Oli1bAIiNjW3i6hpfcXExqampxMbGMnjwYLy9vV3ez+TkZNLT01vk+/nuu+8SFRXFpZde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HBGpnzoqIm3QkCFDXG4XFxfzyCOP0LNnT0JDQwkMDGTXrl31dlT69evn/HNAQADBwcFkZWWd8nh/f386d+7svB0bG+s8vqCggMzMTJcuhcViYfDgwaetYevWrcydO5fAwEDn14QJE7Db7aSlpTmPGzFihMvzRowYwa5duwDYtWsXiYmJLl2nXr16ERoa6jxmy5YtjB079rS1nPjzMJlMxMTEnPbnISL102RakTbo56t3HnnkERYsWMDf//53unTpgp+fH7/4xS+orKw87et4e3u73DaZTNjt9jM63jCMM6zeVXFxMb/61a+4//77T3osKSnpnF77RH5+fvUec6Y/DxGpnzoqIq2Uj48PNputQceuXLmSW265hWnTptG3b19iYmLYv39/0xb4MyEhIURHR7N+/XrnfTabjU2bNp32eYMGDWLnzp106dLlpC8fHx/ncWvWrHF53po1a+jZsycAPXv2JCMjg4yMDOfjO3fuJD8/n169egGObsmiRYvO+TxF5MyooyLSSnXo0IG1a9eyf/9+AgMDCQsLO+WxXbt25bPPPuPyyy/HZDLxxz/+0S2dgPvuu4/Zs2fTpUsXevTowcsvv8yxY8cwmUynfM6jjz7Keeedx8yZM7n99tsJCAhg586dLFiwgFdeecV53MqVK3nmmWeYOnUqCxYs4JNPPuGbb74BYNy4cfTt25cZM2bwwgsvUF1dzT333MOFF17oHCZ7/PHHGTt2LJ07d+a6666jurqab7/9lkcffbRpfygibZw6KiKt1COPPILFYqFXr15ERkaedr7Jc889R7t27Rg5ciSXX345EyZMYNCgQc1YrcOjjz7K9OnTuemmmxgxYoRzvomvr+8pn9OvXz+WLVvGnj17uOCCCxg4cCCPPfYYcXFxLsc9/PDDbNiwgYEDB/KXv/yF5557jgkTJgCOIZovvviCdu3aMXr0aMaNG0enTp34+OOPnc8fM2YMn3zyCV9++SUDBgzg4osvZt26dU3zgxARJ5NxrgPEIiJNxG6307NnT6655hqefPLJs36dDh068OCDD/Lggw82XnEi0iw09CMiHuPAgQP88MMPXHjhhVRUVPDKK6+QlpbG9ddf7+7SRMRNNPQjIh7DbDYzd+5chg4dyqhRo9i+fTsLFy50TnoVkbZHQz8iIiLisdRREREREY+loCIiIiIeS0FFREREPJaCioiIiHgsBRURERHxWAoqIiIi4rEUVERERMRjKaiIiIiIx/p/D50COxaWj4sAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 多层循环神经网络\n",
    "class DeepRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size, num_layers, dropout=0.):\n",
    "        super(DeepRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self._flat_weight_names = []\n",
    "        self._all_weights = []\n",
    "        self.drop = nn.Dropout(p=dropout)\n",
    "        # 定义每一层循环神经网络的参数，由于参数数量不固定，\n",
    "        # 因此使用统一的命名方法更方便调用和管理\n",
    "        for layer in range(num_layers):\n",
    "            W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "            W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "            b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "            layer_params = (W_xh, W_hh, b_h)\n",
    "            params_names = [f'W_xh_l{layer}', f'W_hh_l{layer}', \\\n",
    "                f'b_h_l{layer}']\n",
    "            \n",
    "            # 将新的参数加入到成员列表中\n",
    "            for name, param in zip(params_names, layer_params):\n",
    "                setattr(self, name, param)\n",
    "            self._flat_weight_names.extend(params_names)\n",
    "            self._all_weights.append(params_names)\n",
    "            input_size = hidden_size\n",
    "        self._flat_weights = [getattr(self, wn) if hasattr(self, wn) \\\n",
    "            else None for wn in self._flat_weight_names]\n",
    "    \n",
    "    def __setattr__(self, attr, value):\n",
    "        if hasattr(self, '_flat_weight_names') and \\\n",
    "            attr in self._flat_weight_names:\n",
    "            idx = self._flat_weight_names.index(attr)\n",
    "            self._flat_weights[idx] = value\n",
    "        super().__setattr__(attr, value)\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((self.num_layers, batch_size, hidden_size), \n",
    "            dtype=torch.float),)\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        layer_hidden_states, = states\n",
    "        layer_h_t = []\n",
    "        input_states = inputs\n",
    "        # 需要保存每一层的输出作为下一层的输入\n",
    "        for layer in range(self.num_layers):\n",
    "            hiddens = []\n",
    "            hidden_state = layer_hidden_states[layer]\n",
    "            for step in range(seq_len):\n",
    "                xh = torch.mm(input_states[step], \n",
    "                    getattr(self, f'W_xh_l{layer}'))\n",
    "                hh = torch.mm(hidden_state, getattr(self, f'W_hh_l{layer}'))\n",
    "                hidden_state = xh + hh + getattr(self, f'b_h_l{layer}')\n",
    "                hidden_state = self.drop(torch.tanh(hidden_state))\n",
    "                hiddens.append(hidden_state)\n",
    "            input_states = torch.stack(hiddens, dim=0)\n",
    "            layer_h_t.append(hidden_state)\n",
    "        return input_states, torch.stack(layer_h_t, dim=0)\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "deep_rnn = DeepRNN(128, 128, 2)\n",
    "train_rnn_lm(data_loader, deep_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0f1be39",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "需要注意的是，双向循环神经网络在每个位置的输出同时包含了来自左边和右边的信息，也就是整个输入序列的信息。所以双向循环神经网络并不能用于语言模型，因为语言模型需要仅根据序列中每个词左边的信息来预测这个词。\n",
    "\n",
    "下面的双向循环神经网络是一个简单的示例，要求一次只能输入一个序列。如果想在一个批次中并行处理不同长度的输入序列以获得更高的运行效率，可以通过填充将不同长度的输入对齐。单向循环神经网络的填充较为简单，只需在每个序列末尾添加字符就可以。但是双向循环神经网络的填充更加复杂，正向和反向循环神经网络的读取顺序相反，难以保证两个方向的循环神经网络都填充在末尾，实现起来较为困难。\n",
    "解决方案参考PyTorch中的pack_padded_sequence和pad_packed_sequence。双向循环神经网络不能用于训练语言模型，因此不再提供训练示例代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0344d588",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 双向循环神经网络\n",
    "class BiRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(BiRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 正向循环神经网络参数\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "        # 反向循环神经网络参数\n",
    "        self.W_xh_reverse = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh_reverse = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h_reverse = nn.Parameter(torch.zeros(hidden_size))\n",
    "        \n",
    "    # 分别为正向和反向循环神经网络准备初始状态\n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size), dtype=torch.float),\n",
    "               torch.zeros((batch_size, hidden_size), dtype=torch.float))\n",
    "    \n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, reverse_hidden_state = states\n",
    "        hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            hiddens.append(hidden_state)\n",
    "        reverse_hiddens = []\n",
    "        for step in range(seq_len-1, -1, -1):\n",
    "            xh = torch.mm(inputs[step], self.W_xh_reverse)\n",
    "            hh = torch.mm(reverse_hidden_state, self.W_hh_reverse)\n",
    "            reverse_hidden_state = xh + hh + self.b_h_reverse\n",
    "            reverse_hidden_state = torch.tanh(reverse_hidden_state)\n",
    "            reverse_hiddens.insert(0, reverse_hidden_state)\n",
    "        # 将正向和反向循环神经网络输出的隐状态拼接在一起\n",
    "        combined_hiddens = []\n",
    "        for h1, h2 in zip(hiddens, reverse_hiddens):\n",
    "            combined_hiddens.append(torch.cat([h1, h2], dim=-1))\n",
    "        return torch.stack(combined_hiddens, dim=0), ()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b79ef2c6",
   "metadata": {},
   "source": [
    "下面实现一个带有缩放点乘注意力的循环神经网络，并用其训练语言模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b5c32275",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch:   0%|                        | 0/200 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=1.0058: 100%|█| 200/200 [22:43<00:00,  6.82s\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "class AttentionRNN(nn.Module):\n",
    "    def __init__(self, input_size, hidden_size):\n",
    "        super(AttentionRNN, self).__init__()\n",
    "        self.input_size = input_size\n",
    "        self.hidden_size = hidden_size\n",
    "        # 循环神经网络参数\n",
    "        self.W_xh = nn.Parameter(normal((input_size, hidden_size)))\n",
    "        self.W_hh = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_h = nn.Parameter(torch.zeros(hidden_size))\n",
    "    \n",
    "    def init_rnn_state(self, batch_size, hidden_size):\n",
    "        return (torch.zeros((batch_size, hidden_size),\\\n",
    "            dtype=torch.float),)\n",
    "    \n",
    "    # 缩放点乘注意力\n",
    "    def attention(self, query, keys, values):\n",
    "        \"\"\"\n",
    "        query: batch_size * hidden_size\n",
    "        keys/values: batch_size * prev_len * hidden_size\n",
    "        \"\"\"\n",
    "        # batch_size * 1 * hidden_size\n",
    "        query = torch.unsqueeze(query, 1)\n",
    "        # batch_size * hidden_size * prev_len\n",
    "        keys = torch.permute(keys, (0, 2, 1))\n",
    "        # batch_size * 1 * prev_len\n",
    "        attention_scores = torch.bmm(query, keys) / np.sqrt(\\\n",
    "            self.hidden_size)\n",
    "        # batch_size * 1 * prev_len\n",
    "        attention_weights = F.softmax(attention_scores, dim=1)\n",
    "        # batch_size * hidden_size\n",
    "        attention_state = torch.squeeze(torch.bmm(attention_weights,\\\n",
    "            values))\n",
    "        return attention_state\n",
    "\n",
    "    def forward(self, inputs, states):\n",
    "        seq_len, batch_size, _ = inputs.shape\n",
    "        hidden_state, = states\n",
    "        hiddens = []\n",
    "        attention_hiddens = []\n",
    "        for step in range(seq_len):\n",
    "            xh = torch.mm(inputs[step], self.W_xh)\n",
    "            hh = torch.mm(hidden_state, self.W_hh)\n",
    "            hidden_state = xh + hh + self.b_h\n",
    "            hidden_state = torch.tanh(hidden_state)\n",
    "            \n",
    "            if step > 0:\n",
    "                # batch_size * hidden_size\n",
    "                query = hidden_state\n",
    "                # batch_size * prev_len * hidden_size\n",
    "                keys = values = torch.permute(torch.stack(hiddens,\\\n",
    "                    dim=0), (1, 0, 2))\n",
    "                \n",
    "                attention_state = self.attention(query, keys, values)                \n",
    "                attention_hiddens.append(attention_state)\n",
    "            else:\n",
    "                # 第0步，历史隐状态为空，无法进行注意力运算，\n",
    "                # 直接用隐状态填充\n",
    "                attention_hiddens.append(hidden_state)\n",
    "                \n",
    "            hiddens.append(hidden_state)\n",
    "        return torch.stack(attention_hiddens, dim=0), \\\n",
    "            (attention_state,)\n",
    "    \n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, dtype=torch.long), \n",
    "    batch_size=16, shuffle=True)\n",
    "\n",
    "attention_rnn = AttentionRNN(128, 128)\n",
    "train_rnn_lm(data_loader, attention_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c95d2f4b",
   "metadata": {},
   "source": [
    "下面是多头注意力的代码实现。我们在实现AttentionRNN时将注意力计算封装在成员函数里面，因此实现多头注意力时可以直接继承AttentionRNN类，只用改写构造函数和attention()成员方法即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "6373e7ab",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch:   0%|                        | 0/200 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-199, loss=1.3865: 100%|█| 200/200 [52:16<00:00, 15.68s\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"\n",
    "部分代码参考了GitHub项目d2l-ai/d2l-zh的思路\n",
    "（Copyright (c) 2022 Aston Zhang, Zachary C. Lipton,\n",
    "Mu Li, and Alexander J. Smola, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 多头注意力循环神经网络\n",
    "class MultiHeadAttentionRNN(AttentionRNN):\n",
    "    def __init__(self, input_size, hidden_size, num_heads=4):\n",
    "        super().__init__(input_size, hidden_size)\n",
    "        # 简单起见，一般要求hidden_size能够被num_heads整除\n",
    "        assert hidden_size % num_heads == 0\n",
    "        self.num_heads = num_heads\n",
    "        # 多头注意力参数，用于将查询、键、值映射到子空间\n",
    "        self.W_aq = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_aq = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_ak = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_ak = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_av = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_av = nn.Parameter(torch.zeros(hidden_size))\n",
    "        self.W_ac = nn.Parameter(normal((hidden_size, hidden_size)))\n",
    "        self.b_ac = nn.Parameter(torch.zeros(hidden_size))\n",
    "\n",
    "    # 多头缩放点乘注意力\n",
    "    def attention(self, query, keys, values):\n",
    "        \"\"\"\n",
    "        query: batch_size * hidden_size\n",
    "        keys/values: batch_size * prev_len * hidden_size\n",
    "        \"\"\"\n",
    "        query = torch.mm(query, self.W_aq) + self.b_aq\n",
    "        ori_shape = keys.size()\n",
    "        \n",
    "        keys = torch.reshape(torch.mm(torch.flatten(keys, \n",
    "                start_dim=0, end_dim=1), self.W_ak) + \n",
    "                self.b_ak, ori_shape)\n",
    "        values = torch.reshape(torch.mm(torch.flatten(values, \n",
    "                start_dim=0, end_dim=1), self.W_av) + \n",
    "                self.b_av, ori_shape)\n",
    "        # batch_size * 1 * hidden_size\n",
    "        query = torch.unsqueeze(query, 1)\n",
    "        # batch_size * hidden_size * prev_len\n",
    "        keys = torch.permute(keys, (0, 2, 1))\n",
    "        \n",
    "        head_size = self.hidden_size // self.num_heads\n",
    "        query = torch.split(query, head_size, 2)\n",
    "        keys = torch.split(keys, head_size, 1)\n",
    "        values = torch.split(values, head_size, 2)\n",
    "        \n",
    "        heads = []\n",
    "        for i in range(self.num_heads):\n",
    "            # batch_size * 1 * prev_len\n",
    "            head_scores = torch.bmm(query[i], keys[i]) / np.sqrt(\n",
    "                self.hidden_size // self.num_heads) \n",
    "            # batch_size * 1 * prev_len\n",
    "            head_weights = F.softmax(head_scores, dim=1)\n",
    "            # batch_size * head_size\n",
    "            head_state = torch.squeeze(torch.bmm(head_weights, \n",
    "                values[i])) \n",
    "            heads.append(head_state)\n",
    "        heads = torch.cat(heads, dim=1)        \n",
    "        attention_state = torch.mm(heads, self.W_ac) + self.b_ac\n",
    "\n",
    "        return attention_state\n",
    "\n",
    "data_loader = DataLoader(torch.tensor(sent_tokens, \n",
    "    dtype=torch.long), batch_size=16, shuffle=True)\n",
    "\n",
    "mha_rnn = MultiHeadAttentionRNN(128, 128)\n",
    "train_rnn_lm(data_loader, mha_rnn, vocab_size, hidden_size=128, \n",
    "    epochs=200, learning_rate=1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "166d4dce",
   "metadata": {},
   "source": [
    "下面来实现Transformer模型，包括加入了位置编码的嵌入层、缩放点乘注意力、多头注意力、层归一化等具体实现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "0e4110a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "代码修改自GitHub项目huggingface/transformers\n",
    "（Copyright (c) 2020, The HuggingFace Team, Apache-2.0 License（见附录））\n",
    "\"\"\"\n",
    "# 实现Transformer模型\n",
    "class EmbeddingLayer(nn.Module):\n",
    "    def __init__(self, vocab_size, max_len, embed_size):\n",
    "        super().__init__()\n",
    "        self.vocab_size = vocab_size\n",
    "        self.max_len = max_len\n",
    "        self.embed_size = embed_size\n",
    "        self.word_embedding = nn.Embedding(vocab_size, embed_size)\n",
    "        self.pos_embedding = nn.Embedding(max_len, embed_size)\n",
    "        \n",
    "    def forward(self, input_ids, pos_ids):\n",
    "        \"\"\"\n",
    "        input_ids/pos_ids: batch_size * seq_len\n",
    "        return: batch_size * seq_len * embed_size\n",
    "        \"\"\"\n",
    "        word_embed = self.word_embedding(input_ids)\n",
    "        pos_embed = self.pos_embedding(pos_ids)\n",
    "        # 将词嵌入和位置嵌入相加得到嵌入层输出\n",
    "        return word_embed + pos_embed\n",
    "\n",
    "# 缩放点乘注意力\n",
    "class ScaledDotProductAttention(nn.Module):\n",
    "    def __init__(self, dropout):\n",
    "        super().__init__()\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "    \n",
    "    def forward(self, queries, keys, values, attention_mask):\n",
    "        \"\"\"\n",
    "        queries/keys/values: batch_size * seq_len * hidden_size\n",
    "        attention_mask: batch_size * seq_len * seq_len\n",
    "        return: batch_size * seq_len * hidden_size\n",
    "        \"\"\"\n",
    "        d = queries.size(-1)\n",
    "        # 根据点乘注意力的矩阵形式计算注意力分数，除以查询向量或键向量\n",
    "        # 维度的平方根，即为缩放点乘注意力\n",
    "        scores = torch.bmm(queries, torch.transpose(keys, 1, 2)) / np.sqrt(d)\n",
    "        # 将掩码为0的位置的注意力分数设为一个大负数，根据softmax函数\n",
    "        # 的性质，这些注意力分数归一化后接近0\n",
    "        scores[attention_mask == 0] = -1e6\n",
    "        self.attention_weights = F.softmax(scores, dim=-1)\n",
    "        return torch.bmm(self.dropout(self.attention_weights), values)\n",
    "    \n",
    "class MultiHeadSelfAttention(nn.Module):\n",
    "    def __init__(self, hidden_size, num_heads, dropout):\n",
    "        super().__init__()\n",
    "        assert hidden_size % num_heads == 0\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_heads = num_heads\n",
    "        self.W_q = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_k = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_v = nn.Linear(hidden_size, hidden_size)\n",
    "        self.W_o = nn.Linear(hidden_size, hidden_size)\n",
    "        self.attention = ScaledDotProductAttention(dropout)\n",
    "    \n",
    "    def transpose_qkv(self, states):\n",
    "        # 将长度为hidden_size的向量分成num_heads个长度相等的向量\n",
    "        states = states.reshape(states.shape[0], states.shape[1],\\\n",
    "            self.num_heads, self.hidden_size // self.num_heads)\n",
    "        states = torch.permute(states, (0, 2, 1, 3))\n",
    "        return states.reshape(-1, states.shape[2], states.shape[3])\n",
    "    \n",
    "    # 与transpose_qkv的变换相反\n",
    "    def transpose_output(self, states):\n",
    "        states = states.reshape(-1, self.num_heads, states.shape[1],\\\n",
    "            states.shape[2])\n",
    "        states = torch.permute(states, (0, 2, 1, 3))\n",
    "        return states.reshape(states.shape[0], states.shape[1], -1)\n",
    "    \n",
    "    def forward(self, queries, keys, values, attention_mask):\n",
    "        \"\"\"\n",
    "        querys/keys/values: batch * seq_len * hidden_size\n",
    "        attention_mask: batch * seq_len * seq_len\n",
    "        return:\n",
    "        \"\"\"\n",
    "        # (batch_size * num_heads) * seq_len * (hidden_size / num_heads)\n",
    "        queries = self.transpose_qkv(self.W_q(queries))\n",
    "        keys = self.transpose_qkv(self.W_k(keys))\n",
    "        values = self.transpose_qkv(self.W_v(values))\n",
    "        # 重复张量的元素，用以支持多个注意力头的运算\n",
    "        # (batch_size * num_heads) * seq_len * seq_len\n",
    "        attention_mask = torch.repeat_interleave(attention_mask,\\\n",
    "            repeats=self.num_heads, dim=0)\n",
    "        # (batch_size * num_heads) * seq_len * (hidden_size / num_heads)\n",
    "        output = self.attention(queries, keys, values, attention_mask)\n",
    "        # batch * seq_len * hidden_size\n",
    "        output_concat = self.transpose_output(output)\n",
    "        return self.W_o(output_concat)\n",
    "\n",
    "# 两层前馈神经网络\n",
    "class PositionWiseFNN(nn.Module):\n",
    "    def __init__(self, hidden_size, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.dense1 = nn.Linear(hidden_size, intermediate_size)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.dense2 = nn.Linear(intermediate_size, hidden_size)\n",
    "        \n",
    "    def forward(self, X):\n",
    "        return self.dense2(self.relu(self.dense1(X)))\n",
    "\n",
    "# 层归一化\n",
    "class LayerNorm(nn.Module):\n",
    "    def __init__(self, normalized_shape, eps=1e-6):\n",
    "        super().__init__()\n",
    "        self.gamma = nn.Parameter(torch.ones(normalized_shape))\n",
    "        self.beta = nn.Parameter(torch.zeros(normalized_shape))\n",
    "        # 一个小量用于数值稳定（防止除0）\n",
    "        self.eps = eps\n",
    "        \n",
    "    def forward(self, hidden_states):\n",
    "        mean = torch.mean(hidden_states, -1, keepdim=True)\n",
    "        std = torch.std(hidden_states, -1, keepdim=True)\n",
    "        return self.gamma * (hidden_states - mean) / (std +\\\n",
    "            self.eps) + self.beta\n",
    "\n",
    "# 将两个输入相加并归一化\n",
    "class AddNorm(nn.Module):\n",
    "    def __init__(self, hidden_size, dropout):\n",
    "        super().__init__()\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "        self.layer_norm = LayerNorm(hidden_size)\n",
    "        \n",
    "    def forward(self, X, Y):\n",
    "        return self.layer_norm(self.dropout(Y) + X)\n",
    "    \n",
    "# 一个完整的Transformer层\n",
    "class TransformerLayer(nn.Module):\n",
    "    def __init__(self, hidden_size, num_heads, dropout, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.self_attention = MultiHeadSelfAttention(hidden_size,\\\n",
    "            num_heads, dropout)\n",
    "        self.add_norm1 = AddNorm(hidden_size, dropout)\n",
    "        self.fnn = PositionWiseFNN(hidden_size, intermediate_size)\n",
    "        self.add_norm2 = AddNorm(hidden_size, dropout)\n",
    "    \n",
    "    def forward(self, X, attention_mask):\n",
    "        Y = self.add_norm1(X, self.self_attention(X, X, X, attention_mask))\n",
    "        return self.add_norm2(Y, self.fnn(Y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2fd3f8f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在Transformer模型基础上加上语言模型需要的输入输出、损失计算等\n",
    "class TransformerLM(nn.Module):\n",
    "    def __init__(self, vocab_size, max_len, hidden_size, num_layers,\\\n",
    "                 num_heads, dropout, intermediate_size):\n",
    "        super().__init__()\n",
    "        self.embedding_layer = EmbeddingLayer(vocab_size, max_len,\\\n",
    "            hidden_size)\n",
    "        self.num_layers = num_layers\n",
    "        # 使用ModuleList保存多个Transformer层，注意不能使用Python列表，\n",
    "        # Python列表保存的PyTorch变量无法自动求导\n",
    "        self.layers = nn.ModuleList([TransformerLayer(hidden_size,\\\n",
    "            num_heads, dropout, intermediate_size)\\\n",
    "            for _ in range(num_layers)])\n",
    "        self.output_layer = nn.Linear(hidden_size, vocab_size)\n",
    "        \n",
    "    def forward(self, input_ids):\n",
    "        # 这里实现的forward()函数一次只能处理一句话，\n",
    "        # 如果想要支持批次运算，实现起来会更复杂，也会引入冗余操作\n",
    "        seq_len = input_ids.size(0)\n",
    "        assert input_ids.ndim == 1 and seq_len <= \\\n",
    "            self.embedding_layer.max_len\n",
    "        \n",
    "        # 1 * seq_len\n",
    "        input_ids = torch.unsqueeze(input_ids, dim=0)\n",
    "        pos_ids = torch.unsqueeze(torch.arange(seq_len), dim=0)\n",
    "        # 定义下三角掩码，用于语言模型训练\n",
    "        # 1 * seq_len * seq_len\n",
    "        attention_mask = torch.unsqueeze(torch.tril(torch.ones((seq_len,\\\n",
    "            seq_len), dtype=torch.int32)), dim=0)\n",
    "        # 1 * seq_len * hidden_size\n",
    "        hidden_states = self.embedding_layer(input_ids, pos_ids)\n",
    "        for layer in self.layers:\n",
    "            hidden_states = layer(hidden_states, attention_mask)\n",
    "        outputs = self.output_layer(hidden_states)\n",
    "        \n",
    "        loss_fct = nn.CrossEntropyLoss(ignore_index=0)\n",
    "        loss = loss_fct(outputs[:, :-1].squeeze(),\\\n",
    "            input_ids[:, 1:].squeeze())\n",
    "        return loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "e459fc19",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-0, loss=7.0767:   0%|          | 0/50 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch-49, loss=1.2895: 100%|█| 50/50 [06:35<00:00,  7.90s/it\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练TransformerLM，由于不再采取批次训练，因此不再使用RNNLM和data_loader\n",
    "def train_transformer_lm(data, model, epochs=50, learning_rate=1e-3):\n",
    "    optimizer = Adam(model.parameters(), lr=learning_rate)\n",
    "    model.zero_grad()\n",
    "    model.train()\n",
    "    \n",
    "    epoch_loss = []\n",
    "    with trange(epochs, desc='epoch', ncols=60) as pbar:\n",
    "        for epoch in pbar:\n",
    "            step_loss = []\n",
    "            np.random.shuffle(data)\n",
    "            for step, x in enumerate(data):\n",
    "                loss = model(torch.tensor(x, dtype=torch.long))\n",
    "                pbar.set_description(f'epoch-{epoch},'+\\\n",
    "                    f' loss={loss.item():.4f}')\n",
    "                loss.backward()\n",
    "                grad_clipping(model)\n",
    "                optimizer.step()\n",
    "                model.zero_grad()\n",
    "                step_loss.append(loss.item())\n",
    "            # 本章前面的模型训练使用batch_size为16，\n",
    "            # TransformerLM出于简便实现只能使用batch_size为1\n",
    "            # 因此TransformerLM每一步的损失方差会更大，\n",
    "            # 为便于对比，取每个epoch最后16个样本的平均损失\n",
    "            epoch_loss.append(np.mean(step_loss[-16:]))\n",
    "    \n",
    "    epoch_loss = np.array(epoch_loss)\n",
    "    plt.plot(range(len(epoch_loss)), epoch_loss)\n",
    "    plt.xlabel('training epoch')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "    \n",
    "sent_tokens = dataset.convert_tokens_to_ids()\n",
    "max_len=40\n",
    "for i, tokens in enumerate(sent_tokens):\n",
    "    tokens = tokens[:max_len]\n",
    "    tokens += [0] * (max_len - len(tokens))\n",
    "    sent_tokens[i] = tokens\n",
    "sent_tokens = np.array(sent_tokens)\n",
    "\n",
    "model = TransformerLM(vocab_size, max_len=40, hidden_size=128,\\\n",
    "    num_layers=1, num_heads=4, dropout=0., intermediate_size=512)\n",
    "train_transformer_lm(sent_tokens, model)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
